perm filename ISSUES.2[COM,LSP] blob
sn#874736 filedate 1989-06-23 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00007 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 ∂23-Jun-89 1049 X3J13-mailer Issue: ADJUST-ARRAY-NOT-ADJUSTABLE (version 11)
C00022 00003 ∂23-Jun-89 1049 X3J13-mailer Issue: DATA-IO (version 8)
C00042 00004 ∂23-Jun-89 1050 X3J13-mailer Issue: MAP-INTO (version 3)
C00049 00005 ∂23-Jun-89 1051 X3J13-mailer Issue: PATHNAME-LOGICAL (version 4)
C00103 00006 ∂23-Jun-89 1052 X3J13-mailer Issue: PATHNAME-WILD (version 7)
C00131 00007 ∂23-Jun-89 1234 X3J13-mailer issue CLOS-MACRO-COMPILATION, version 5
C00144 ENDMK
C⊗;
∂23-Jun-89 1049 X3J13-mailer Issue: ADJUST-ARRAY-NOT-ADJUSTABLE (version 11)
Received: from STONY-BROOK.SCRC.Symbolics.COM by SAIL.Stanford.EDU with TCP; 23 Jun 89 10:49:01 PDT
Received: from KENNETH-WILLIAMS.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via INTERNET with SMTP id 616029; 23 Jun 89 13:50:43 EDT
Date: Fri, 23 Jun 89 13:49 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Issue: ADJUST-ARRAY-NOT-ADJUSTABLE (version 11)
To: X3J13@sail.stanford.edu
Message-ID: <19890623174903.2.MOON@KENNETH-WILLIAMS.SCRC.Symbolics.COM>
Version 5 of this proposal passed with amendments at the January
1989 X3J13 meeting. However, the amendments were found to result
in an inconsistent proposal, and it was also pointed out that some
related problems with simple-arrays were not addressed. Since then
there has been a great deal of private discussion, and review of
various versions of the proposal including ones earlier than 5.
The result is this proposal, which is believed to be acceptable to
everyone and is being offered for a vote in June to replace the
January version that was already voted in.
This version has been amended based on last minute discussion: the
statement that ADJUST-ARRAY, when it copies, can destroy the original has
been removed. A remark about VECTOR-PUSH-EXTEND has been added. These
changes are in points 4 and f. In the discussion section I mentioned
suggestions to get rid of ADJUSTABLE-ARRAY-P.
Issue: ADJUST-ARRAY-NOT-ADJUSTABLE
References: ADJUST-ARRAY (p297), ADJUSTABLE-ARRAY-P (p293),
MAKE-ARRAY (pp286-289), simple arrays (p28, 289),
simple strings with fill pointers (p299),
VECTOR-PUSH-EXTEND (p296)
Category: CLARIFICATION and CHANGE
Edit history: 22-Apr-87, Version 1 by Pitman
15-Nov-88, Versions 2a,2b,2c by Pitman
02-Dec-88, Version 3 by Pitman
11-Jan-89, Version 4 by Pitman
16-Jan-89, Version 5, by Gabriel. Amended at the meeting to shorten.
23-Jan-89, Version 6, by Moon. Shorten without the bug introduced
by the amendment, add clarification of SIMPLE-ARRAY type.
15-Feb-89, Version 7, by Pitman. Minor changes per comments from
RPG and Dalton.
11-Mar-89, Version 8, by Pitman. Change category, add endorsements.
17-Mar-89, Version 9, by Moon, fix wording and examples to make it
clear that the semantics of simple-array is unchanged.
6-Jun-89, Version 10, by Moon and Gabriel, do over.
23-Jun-89, Version 11, by Moon, two little corrections
Problem Description:
There are a number of unclear passages in CLtL related to simple arrays
and adjustable arrays. There is disagreement on precisely how these
passages are to be interpreted, and no one is happy with the fact that
ADJUST-ARRAY works only on an implementation-dependent subset of arrays.
The description of the :ADJUSTABLE option to MAKE-ARRAY on p288 says that
``the argument, if specified and not NIL, indicates that it must be
possible to alter the array's size dynamically after it is created. This
argument defaults to NIL.'' The description of the :ADJUSTABLE option
does not say what MAKE-ARRAY will do if the argument is unsupplied or
explicitly NIL.
The description of ADJUSTABLE-ARRAY-P on p293 says that it is true ``if
the argument (which must be an array) is adjustable, and otherwise
false.'' However, the description of MAKE-ARRAY makes it clear that this
is not necessarily the same as asking if the array was created with
:ADJUSTABLE T. If ADJUSTABLE-ARRAY-P returns NIL, you know that
:ADJUSTABLE NIL was supplied (or no :ADJUSTABLE option was supplied), but
if ADJUSTABLE-ARRAY-P returns T, then there is no information about
whether :ADJUSTABLE was used.
The description of ADJUST-ARRAY on pp297-298 says that it is ``not
permitted to call ADJUST-ARRAY on an array that was not created with the
:ADJUSTABLE option.'' This is inconsistent with ADJUSTABLE-ARRAY-P.
The definition of SIMPLE-ARRAY on p.28 says ``an array that is not
displaced to another array, has no fill pointer, and is not to have its
size adjusted dynamically after creation is called a simple array.''
It is left unclear whether this is an implication or an equivalence,
i.e. whether there can be other simple arrays as well.
CLtL p.299 appears to refer to simple strings with fill pointers,
suggesting that it is an implication, but similar language is used for
equivalences in other parts of CLtL.
Proposal (ADJUST-ARRAY-NOT-ADJUSTABLE:IMPLICIT-COPY)
1. If MAKE-ARRAY is called with the :ADJUSTABLE, :FILL-POINTER,
and :DISPLACED-TO arguments each either unspecified or false, the
resulting array is a simple array. (This just repeats what CLtL
says on page 289, it's here to aid in understanding the next point.)
2. If MAKE-ARRAY is called with one or more of the :ADJUSTABLE,
:FILL-POINTER, or :DISPLACED-TO arguments true, whether the
resulting array is simple is unspecified.
3. It is permitted to call ADJUST-ARRAY on any array. (Remove the
restriction documented at the bottom of p.297.)
4. If ADJUST-ARRAY is applied to an array created with :ADJUSTABLE true,
the array returned is EQ to its first argument. It is not specified
whether ADJUST-ARRAY returns an array EQ to its first argument for any
other arrays. If the array returned by ADJUST-ARRAY is not EQ to its
first argument, the original array is unchanged and does not share
storage with the new array.
5. The predicate ADJUSTABLE-ARRAY-P is true if and only if ADJUST-ARRAY
will return a value EQ to this array when given this array as its first
argument.
Clarifications and Logical Consequences:
a. There is no specified way to create an array for which ADJUSTABLE-ARRAY-P
definitely returns NIL.
b. There is no specified way to create an array that is non-simple.
c. The definition of SIMPLE-ARRAY on p.28 is taken to be an implication,
not an equivalence. This is either a clarification or a change depending
on one's prior reading of that definition.
d. The meaning of ADJUSTABLE-ARRAY-P is changed.
e. As with such functions as DELETE and NCONC, textbooks should
instruct programmers to be careful to receive the value returned by
ADJUST-ARRAY, as it might not be EQ to the first argument.
f. VECTOR-PUSH-EXTEND still signals an error if given a non-adjustable
array. ADJUST-ARRAY's new feature of making a copy cannot be used
by VECTOR-PUSH-EXTEND, since there is no way to return the copy to
the caller.
Rationale:
Points 3 and 4 eliminate the problem of ADJUST-ARRAY only working on a
subset of arrays, by changing it to work on all arrays. It remains
implementation-dependent whether the array is modified in place or
copied, i.e. whether the result is EQ to the argument, however many other
functions in Common Lisp have similar implementation-dependent behavior.
Implementation-dependent storage allocation or reuse is considered
more benign than implementation-dependent applicability of an operation.
Point 3 recognizes that ADJUST-ARRAY offers features that are offered by
no other function and which are useful in cases involving non-adjustable
arrays (for what amounts to copying). This change would allow an
expression such as:
(SETQ X (ADJUST-ARRAY X ...))
to work reliably. Those desiring the old behavior could do:
(IF (OR (NOT (ADJUSTABLE-ARRAY-P X))
(NOT (EQUAL (ARRAY-RANK X) (LENGTH NEW-DIMENSIONS))))
(ERROR "Array cannot be adjusted."))
to get the old style error checking.
Point 5 recycles the name ADJUSTABLE-ARRAY-P as a test for whether an
array is adjusted in place or by copying.
Point 2 preserves the raison d'etre of simple arrays, which is to provide
a portable interface to implementation-dependent specialized arrays that
trade decreased functionality for faster access. A proposed alternative
was to specify a way to create an array that is guaranteed not to be
simple. This would have made (typep (make-array ...) 'simple-array)
return the same value in all implementations, but would have required
large changes to some implementations and would be of little benefit to
users. Users need to know that certain arrays are simple, so they can
put in declarations and get higher performance, but users have no need to
be able to create arrays that are definitely non-simple (for lower
performance) or definitely non-adjustable.
Examples:
1. The following program is conforming.
(defun double (a)
(adjust-array a (* (length a) 2)))
(double (make-array 30))
2. The following program is conforming. In no implementation is the
type declaration violated.
(let ((a (make-array 100)))
(declare (simple-array a))
(frob a))
3. The following program is non-conforming. The consequences of this
program are undefined because the type declaration is violated in some
implementations.
(let ((a (make-array 100 :adjustable t)))
(declare (simple-array a))
(frob a))
Current Practice:
Every correct CLtL implementation conforms to points 1 and 2. It is
unlikely that any implementation currently exists that conforms to points
3, 4, and 5. Points 3 and 4 involve additions to an implementation to
support the copying form of ADJUST-ARRAY. Point 5 may involve a change
to ADJUSTABLE-ARRAY-P or may be able to use the existing implementation
of the function.
Symbolics Genera makes :ADJUSTABLE NIL arrays adjustable in most cases,
and ignores adjustability in deciding whether an array is a SIMPLE-ARRAY.
The arrays that are internally simple in Symbolics Genera are a different
subset of arrays from the type SIMPLE-ARRAY, because simplicity in that
implementation depends on the rank and total-size as well as on the
fill-pointer and displacement, thus Genera does not use the type
SIMPLE-ARRAY for anything.
Lucid, IIM, Ibuki, and Symbolics Cloe make :ADJUSTABLE NIL arrays
non-adjustable in all cases, and make every array non-simple that CLTL
does not require to be simple.
Macintosh Allegro Common Lisp v1.2 makes :ADJUSTABLE NIL arrays
non-adjustable in all cases, makes all arrays of rank other than 1
non-simple (violating point 1), and makes every array non-simple that
CLTL does not require to be simple.
Cost to Implementors:
The change to ADJUSTABLE-ARRAY-P is easy. The change to ADJUST-ARRAY may
involve some complex coding but should not be a large task. No changes
are required to anything connected with SIMPLE-ARRAY.
Cost to Users:
None in code that does not call ADJUSTABLE-ARRAY-P. This is a fully
upward-compatible change from the user's standpoint.
Benefits:
Programs that use simple arrays and/or adjust arrays will be easier
to port, as the language specification for these features will be
clearer. More programs will be able to call ADJUST-ARRAY, as its use
will not be restricted to a subset of arrays.
Non-Benefits:
Users who expect adjusting arrays created with :ADJUSTABLE NIL to signal
an error would not get the desired signal. A few programs might have
porting problems due to variation among implementations of whether the
result of ADJUST-ARRAY is EQ to the first argument.
Aesthetics:
Most people believe the status quo is unaesthetic. Having an aspect of
the language more clearly specified is an aesthetic improvement.
Allowing ADJUST-ARRAY on all arrays is an aesthetic improvement.
Discussion:
There are at least 110 messages of discussion preceding this version of the
proposal. It does not seem feasible to summarize them here.
Dick Gabriel, Dave Moon, and Guy Steele support this proposal.
Some commentors would like to get rid of ADJUSTABLE-ARRAY-P, since
ADJUST-ARRAY now works on all arrays. Other commentors have said that
ADJUSTABLE-ARRAY-P is still needed in some applications, such as user
written functions that behave like VECTOR-PUSH-EXTEND, and hence should
be kept; the concept of "adjustable array" is still meaningful.
∂23-Jun-89 1049 X3J13-mailer Issue: DATA-IO (version 8)
Received: from STONY-BROOK.SCRC.Symbolics.COM by SAIL.Stanford.EDU with TCP; 23 Jun 89 10:49:27 PDT
Received: from KENNETH-WILLIAMS.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via INTERNET with SMTP id 616030; 23 Jun 89 13:51:22 EDT
Date: Fri, 23 Jun 89 13:49 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Issue: DATA-IO (version 8)
To: X3J13@sail.stanford.edu
Message-ID: <19890623174939.3.MOON@KENNETH-WILLIAMS.SCRC.Symbolics.COM>
This is a new issue. It arose from an investigation of features
that are plausibly needed but missing from draft ANSI Common Lisp.
This issue seems sufficiently simple and noncontroversial that
I would like to see it on the agenda for the June X3J13 meeting.
This issue has been amended based on last minute discussion. Clarify
that "readable" is defined in terms of "similar as constants" as
defined in issue CONSTANT-COMPILABLE-TYPES. This modifies point 1a and
adds new points 1d, 1e, and 1f. The interaction between *PRINT-READABLY*
and other printer control variables has been tightened; this modifies
point 1c and deletes the old points 1d and 1e.
Issue: DATA-IO
References: CLtL pp.360, 370, 382
Related issues: CONSTANT-COMPILABLE-TYPES
Category: ADDITION
Edit history: Version 1, 9-May-89, by Moon
Version 2, 10-May-89, by Moon
(clarify ambiguities, add PRINT-UNREADABLE-OBJECT)
Version 3, 18-May-89, by Moon (respond to KMP's comments)
Version 4, 21-May-89, by Moon (almost-final cleanup)
Version 5, 22-May-89, by Pitman (``never say never'')
Version 6, 23-May-89, by Moon (final cleanup)
Version 7, 18-Jun-89, by Moon (more fixes based on
discussion in the cleanup subcommittee)
Version 8, 23-Jun-89, by Moon (fixes based on discussion)
Problem description:
Storing data in textual form in files, as Lisp expressions, is common
practice but has some pitfalls. Files can be unreadable if #<...> syntax
is written by the printer, or if the reader syntax or package varies
between writing and reading. Files of data intended to be carried from
one Lisp implementation to another can fail to read correctly if
implementation-dependent syntax extensions get used when not intended.
CLtL p.370 recommends that unreadable objects be printed with #<...>
syntax including implementation-dependent information. Now that users
can write their own PRINT-OBJECT methods, a way is needed for such
methods to print this syntax without any implementation-dependent coding.
Proposal (DATA-IO:ADD-SUPPORT):
1a. Add a new variable *PRINT-READABLY*. Add a corresponding keyword
argument :READABLY to WRITE. The default value of *PRINT-READABLY* is
NIL. If *PRINT-READABLY* is true, then printing any object produces a
printed representation that the reader will accept. The reader will
produce an object that is "similar as a constant" to the object that
was printed. The term "similar as a constant" is defined in the
already accepted compiler issue CONSTANT-COMPILABLE-TYPES:SPECIFY.
If *PRINT-READABLY* is true and printing a readable printed
representation is not possible, the printer signals an error of type
PRINT-NOT-READABLE rather than using an unreadable syntax such as #<...>.
The printed representation produced when *PRINT-READABLY* is true might
or might not be the same as the printed representation produced when
*PRINT-READABLY* is false.
1b. All methods for PRINT-OBJECT must obey *PRINT-READABLY*. This
includes both user-defined methods and implementation-defined methods.
1c. If *PRINT-READABLY* is true and another printer control variable
(*PRINT-LENGTH*, *PRINT-LEVEL*, *PRINT-ESCAPE*, *PRINT-GENSYM*,
*PRINT-ARRAY*, or an implementation-defined printer control variable)
would cause the requirements of point 1a to be violated, that other
printer control variable is ignored.
1d. The printing of interned symbols is not affected by *PRINT-READABLY*,
regardless of the outcome of issue COMPILE-FILE-SYMBOL-HANDLING
(referenced by issue CONSTANT-COMPILABLE-TYPES).
1e. Note that the "similar as a constant" rule for readable printing
implies that #A or #( syntax cannot be used for arrays of element-type
other than T. An implementation will have to use another syntax or
signal a PRINT-NOT-READABLE error. A PRINT-NOT-READABLE error will not
be signalled for strings or bit-vectors.
1f. Readable printing of structures and standard-objects is controlled
by their PRINT-OBJECT method, not by their MAKE-LOAD-FORM method.
"Similarity as a constant" for these objects is application dependent
and hence is defined to be whatever these methods do.
2. Add a new reader control variable, *READ-EVAL*, whose default value is
T. If *READ-EVAL* is NIL, the #. reader macro signals an error. If
*READ-EVAL* is false and *PRINT-READABLY* is true, any PRINT-OBJECT
method that would output a #. reader macro either outputs something
different or signals an error of type PRINT-NOT-READABLE.
3. Add a new macro:
WITH-STANDARD-IO-SYNTAX &body body [Macro]
Within the dynamic extent of <body>, all reader/printer control
variables, including any implementation-defined ones not specified by
Common Lisp, are bound to values that produce standard read/print
behavior. The values for Common Lisp specified variables are:
*PACKAGE* The USER package
*PRINT-ARRAY* T
*PRINT-BASE* 10
*PRINT-CASE* :UPCASE
*PRINT-CIRCLE* NIL
*PRINT-ESCAPE* T
*PRINT-GENSYM* T
*PRINT-LENGTH* NIL
*PRINT-LEVEL* NIL
*PRINT-PRETTY* NIL
*PRINT-RADIX* NIL
*PRINT-READABLY* T
*READ-BASE* 10
*READ-DEFAULT-FLOAT-FORMAT* SINGLE-FLOAT
*READ-EVAL* T
*READ-SUPPRESS* NIL
*READTABLE* The standard readtable
The values returned by WITH-STANDARD-IO-SYNTAX are the values
of the last body form, or NIL if there are no body forms.
4. Add a new macro:
PRINT-UNREADABLE-OBJECT (object stream &key type identity) [Macro]
&body body
Output a printed representation of <object> on <stream>, beginning with
"#<" and ending with ">". Everything output to <stream> by the <body>
forms is enclosed in the angle brackets. If :type is true, the body
output is preceded by a brief description of the object's type and a
space character. If :identity is true, the body output is followed by
a space character and a representation of the object's identity,
typically a storage address.
If *PRINT-READABLY* is true, PRINT-UNREADABLE-OBJECT signals an error
of type PRINT-NOT-READABLE without printing anything.
The <object>, <stream>, :type, and :identity arguments are all evaluated
normally. :type and :identity default to false. It is valid to omit
the <body> forms. If :type and :identity are both true and there are no
<body> forms, only one space character separates the type and the identity.
The value returned by PRINT-UNREADABLE-OBJECT is NIL.
5. Add a new condition type:
PRINT-NOT-READABLE [Type]
Errors which occur during output while *PRINT-READABLY* is true, as a
result of attempting to output a printed representation that cannot be
read back, should inherit from this type. This is a subtype of ERROR.
The init keyword :OBJECT is supported to initialize the slot containing
the object being printed, which can be accessed using
PRINT-NOT-READABLE-OBJECT.
Examples:
;; Example #1: Reliable Write-Read
(WITH-OPEN-FILE (FILE pathname :DIRECTION :OUTPUT)
(WITH-STANDARD-IO-SYNTAX
(PRINT DATA FILE)))
; ... Later, in another Lisp:
(WITH-OPEN-FILE (FILE pathname :DIRECTION :INPUT)
(WITH-STANDARD-IO-SYNTAX
(SETQ DATA (READ FILE))))
;; Example #2: Use of PRINT-UNREADABLE-OBJECT
;; Note that in this example, the precise form of the output
;; is really implementation-dependent.
(DEFMETHOD PRINT-OBJECT ((OBJ AIRPLANE) STREAM)
(PRINT-UNREADABLE-OBJECT (OBJ STREAM :TYPE T :IDENTITY T)
(PRINC (TAIL-NUMBER OBJ) STREAM)))
(PRINT MY-AIRPLANE)
#<Airplane NW0773 36000123135> ;in Implementation A
;or
#<FAA:AIRPLANE NW0773 17> ;in Implementation B
Rationale:
1. *PRINT-READABLY* is important so that errors involving data with no
readable printed representation are detected when writing the file, not
later on when the file is read.
*PRINT-READABLY* is different from *PRINT-ESCAPE* because output printed
with escapes only has to be generally recognizable by humans, whereas
output printed readably has to be reliably recognizable by computers.
2. Binding *READ-EVAL* to NIL is useful when reading data that came from
an untrusted source, such as a network or a user-supplied data file, to
prevent the #. reader macro from being exploited as a "Trojan horse" to
cause arbitrary forms to be evaluated.
3. Providing the WITH-STANDARD-IO-SYNTAX macro to bind all the variables,
instead of using LET and explicit bindings of the existing variables,
ensures that nothing is overlooked and avoids problems with
implementation-defined reader/printer control variables.
If the user wishes to use a non-standard value for some variable, such as
*PACKAGE* or *READ-EVAL*, it can be bound by LET inside the body of
WITH-STANDARD-IO-SYNTAX. Similarly, if the user dislikes the somewhat
arbitrary choices of values for *PRINT-CIRCLE* and *PRINT-PRETTY*, they
can be bound to the preferred values inside the body.
4. PRINT-UNREADABLE-OBJECT allows user-written PRINT-OBEJCT methods to
adhere to implementation-specific style without requiring users to write
implementation-dependent code.
5. Defining a specific condition type associated with *PRINT-READABLY*
makes it possible for programs to handle the condition and recognize
the offending object.
Current practice:
Symbolics Genera has had these features for many years, except with
different names. For instance, WITH-STANDARD-IO-SYNTAX is named
WITH-STANDARD-IO-ENVIRONMENT and binds *PACKAGE* to a non-standard
package. The proposed new names are better than the Genera names.
Genera's WITH-STANDARD-IO-ENVIRONMENT also disables #., to prevent trojan
horses, since #. could evaluate an arbitrary form. This is particularly
important for network protocols. WITH-STANDARD-IO-SYNTAX does not bind
*READ-EVAL* to NIL, because that would prevent using #. in the printer
for common datatypes, which is current practice in some implementations
for printing PATHNAMEs or RANDOM-STATEs.
In Genera, PRINT-UNREADABLE-OBJECT is called SYS:PRINTING-RANDOM-OBJECT
and takes slightly different arguments. In PCL, PRINT-UNREADABLE-OBJECT
is called PCL:PRINTING-RANDOM-THING.
Cost to Implementors:
Very small, these features are all easy to add. If #. is output by any
system-supplied print methods, they might want to invent a different
syntax, however that is not required by this proposal.
Cost to Users:
None if they don't use the feature. Otherwise just the cost of
supporting *PRINT-READABLY* or using PRINT-UNREADABLE-OBJECT in their
PRINT-OBJECT methods.
Cost of non-adoption:
There will be no reliable, standard way to write data into a file.
Performance impact:
Negligible. Entering WRITE may be slightly slower since there is
one more keyword argument to parse and one more special variable
to bind before calling PRINT-OBJECT.
Benefits:
Data can be written into files reliably without resorting to
implementation-specific programming.
Esthetics:
Mildly improved.
Discussion:
Pitman and Moon support this proposal.
∂23-Jun-89 1050 X3J13-mailer Issue: MAP-INTO (version 3)
Received: from STONY-BROOK.SCRC.Symbolics.COM by SAIL.Stanford.EDU with TCP; 23 Jun 89 10:50:30 PDT
Received: from KENNETH-WILLIAMS.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via INTERNET with SMTP id 616033; 23 Jun 89 13:52:24 EDT
Date: Fri, 23 Jun 89 13:50 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Issue: MAP-INTO (version 3)
To: X3J13@sail.stanford.edu
Message-ID: <19890623175044.4.MOON@KENNETH-WILLIAMS.SCRC.Symbolics.COM>
This is a new issue. It arose from an investigation of features
that are plausibly needed but missing from draft ANSI Common Lisp.
This issue seems sufficiently simple and noncontroversial that
I would like to see it on the agenda for the June X3J13 meeting.
This version has been revised based on BarMar's suggestions: It can
be called without any argument sequences; if the result sequence is
a vector with a fill-pointer, the fill-pointer's current value is
ignored, and the fill-pointer is set to the number of results produced.
Issue: MAP-INTO
References: none
Related issues: BIT-ARRAY-FUNCTIONS
Category: ADDITION
Edit history: 23-May-89, version 1 by Moon
19-Jun-89, version 2 by Moon (fix arglist)
23-Jun-89, version 3 by Moon (include BarMar's suggestions)
Problem description:
The function MAP is very useful but can be a source of inefficiency
because it conses the result. Sometimes the user has storage
already allocated in which the result could be stored.
Proposal (MAP-INTO:ADD-FUNCTION):
Add the following function:
MAP-INTO result-sequence function &rest sequences [Function]
Destructively modifies the result-sequence to contain the results of
applying function to each element in the argument sequences in turn.
Returns result-sequence.
The arguments result-sequence and each element of sequences can each be
either a list or a vector (one-dimensional array). Note that NIL is
considered to be a sequence, of length zero. If result-sequence and
each element of sequences are not all the same length, the iteration
terminates when the shortest sequence is exhausted. If result-sequence
is a vector with a fill-pointer, the fill-pointer is ignored when
deciding how many iterations to perform, and afterwards the
fill-pointer is set to the number of times function was applied.
If result-sequence is longer than the shortest element of sequences,
extra elements at the end of result-sequence are left unchanged.
MAP-INTO differs from MAP in that it modifies an existing sequence
rather than creating a new one. In addition, MAP-INTO can be called
with only two arguments, while MAP requires at least three arguments.
If result-sequence is NIL, MAP-INTO immediately returns NIL, since
NIL is a sequence of length zero.
If BIT-ARRAY-FUNCTIONS:NO-NEW-FUNCTIONS passes, then MAP-INTO will
allow result-sequence and each element of sequences to be mappables
all of the same rank.
The function must take at least as many arguments as there are
sequences provided.
If function has side effects, it can count on being called first on all
of the elements with index 0, then on all of those numbered 1, and so
on.
Examples:
(map-into x #'+ x y)
(map-into q #'cons keys vals)
(map-into syms #'gensym)
Rationale:
MAP-INTO is a simple way to express reuse of storage that is
stylistically consistent with the rest of Common Lisp.
Current practice:
Symbolics Genera 7.2 implements the proposal.
Cost to Implementors:
Small.
Cost to Users:
None.
Cost of non-adoption:
Small.
Performance impact:
None.
Benefits:
More expressive language.
Esthetics:
User programs won't have to write the above examples as
(loop for xx on x and yy in y do
(setf (car xx) (+ (car xx) yy)))
or something else about equally horrible.
Discussion:
None.
∂23-Jun-89 1051 X3J13-mailer Issue: PATHNAME-LOGICAL (version 4)
Received: from STONY-BROOK.SCRC.Symbolics.COM by SAIL.Stanford.EDU with TCP; 23 Jun 89 10:51:11 PDT
Received: from KENNETH-WILLIAMS.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via INTERNET with SMTP id 616034; 23 Jun 89 13:53:02 EDT
Date: Fri, 23 Jun 89 13:51 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Issue: PATHNAME-LOGICAL (version 4)
To: X3J13@sail.stanford.edu
Message-ID: <19890623175120.5.MOON@KENNETH-WILLIAMS.SCRC.Symbolics.COM>
This is an old issue but it has not been written up before. I'm sorry this
is coming out so late, but it's been quite a struggle to cast it into clear
and easily understood form. It is rather a long proposal in order to be
very clear about exactly what it's proposing, and I apologize for the
length.
This version has been amended and simplified based on last-minute
discussion: Support for back-translation has been removed.
TRANSLATE-LOGICAL-PATHNAME now returns only value, but has added ability
for implementations to add keyword arguments and extra return values.
I also made a minor clarification under LOGICAL-PATHNAME-TRANSLATIONS.
The LOGICAL-DIRECTORY example has been removed, as it is no longer
possible for a user to implement that functionality.
Issue: PATHNAME-LOGICAL
Forum: Cleanup
References: Pathnames (pp410-413)
OPEN (p.418), WITH-OPEN-FILE (p.422), RENAME-FILE (p.423),
DELETE-FILE (p.424), PROBE-FILE (p.424),
FILE-WRITE-DATE (p.424), FILE-AUTHOR (p.424), LOAD (p.426),
COMPILE-FILE (p.439), DIRECTORY (p.427), PATHNAME (p.413),
TRUENAME (p.413), MERGE-PATHNAMES (p.415),
MAKE-PATHNAME (p.416), and PARSE-NAMESTRING (p.414).
Related issues: PATHNAME-CANONICAL-TYPE, PATHNAME-COMPONENT-VALUES,
PATHNAME-SUBDIRECTORY-LIST, and PATHNAME-WILD
Category: ADDITION
Edit history: Version 1, 11-May-89, by Moon
Version 2, 18-May-89, by Moon
Version 3, 21-Jun-89, by Moon (revise based on discussion
in the cleanup committee)
Version 4, 23-Jun-89, by Moon (remove backtranslation)
Problem description:
Pathname values are not portable, but they are sometimes part of a
program, for example the names of files containing the program and the
data used by the program. Moving large programs between sites would
be easier if pathname values did not have to be translated.
Pathname values are nonportable because not all Common Lisp
implementations use the same operating system and file name syntax varies
widely among operating systems. In addition, corresponding files at two
different sites may have different names even when the operating system
is the same; for example, they may be on different directories or
different devices.
The issue of portable pathname values is separate from the issues of
portable pathname operations. See the related issues listed above.
For inter-issue interactions, see the discussion section below.
Note that issue PATHNAME-LOGICAL fundamentally depends on issue
PATHNAME-WILD. If PATHNAME-WILD:NEW-FUNCTIONS does not pass,
PATHNAME-LOGICAL cannot pass.
Proposal (PATHNAME-LOGICAL:ADD):
1. Define a "logical" file system that looks the same at every site.
This file system is implemented by translating each logical pathname into
a physical pathname on a real file system. The logical pathnames are the
same at all sites, but the translations are different at each site, thus
the physical pathnames can be different at each site.
2a. The syntax of a logical pathname namestring is as follows:
[ host ":" ] [ ";" ] { directory ";" }* [ name ] [ "." type [ "." version ]]
2b. Terminology:
A <word> consists of one or more uppercase letters, digits, and hyphens.
A <wildcard word> consists of one or more asterisks, uppercase letters,
digits, and hyphens, including at least one asterisk, with no two
asterisks adjacent. Each asterisk matches a sequence of zero or more
characters. The <wildcard word> "*" parses into :WILD, the others parse
into strings.
In <words> and <wildcard words> lowercase letters are translated to
uppercase. The consequences of using other characters are unspecified.
2c. Logical pathname components:
The host is a <word> that has been defined as a logical pathname host by
using SETF of LOGICAL-PATHNAME-TRANSLATIONS.
There is no device, so the device component of a logical pathname is
always :UNSPECIFIC. No other component can be :UNSPECIFIC.
Each directory is a <word>, a <wildcard word>, or "**" (:WILD-INFERIORS).
If a semicolon precedes the directories, the directory component is
relative, otherwise it is absolute.
The name is a <word> or a <wildcard word>.
The type is a <word> or a <wildcard word>.
The version is a positive decimal integer or "NEWEST" (:NEWEST) or "*"
(:WILD). The letters in "NEWEST" can be in either alphabetic case.
The consequences of using any value not specified here as a logical
pathname component are unspecified.
The null string "" is not a valid value for any component of a logical
pathname, since "" is not a <word> and not a <wildcard word>.
3. Parsing of logical pathname namestrings into logical pathnames
operates as follows:
3a. Logical pathname namestrings are recognized by the LOGICAL-PATHNAME
and TRANSLATE-LOGICAL-PATHNAME functions. In this case the host portion
of the logical pathname namestring and its following colon are required.
3b. The PARSE-NAMESTRING function recognizes a logical pathname
namestring when the host argument is logical or the defaults argument is
a logical pathname. In this case the host portion of the logical
pathname namestring and its following colon are optional. If the host
portion of the namestring and the host argument are both present and do
not match, an error is signalled.
The host argument is logical if it is supplied and came from
PATHNAME-HOST of a logical pathname. Whether a host argument is logical
if it is a string equal to a logical pathname host name is
implementation-defined.
3c. The MERGE-PATHNAMES function recognizes a logical pathname namestring
when the defaults argument is a logical pathname. In this case the host
portion of the logical pathname namestring and its following colon are
optional.
3d. Whether the other functions that coerce strings to pathnames
(PATHNAME, TRUENAME, PARSE-NAMESTRING in other circumstances than those
described in point 3b, MERGE-PATHNAMES in other circumstances than those
described in point 3c, the :DEFAULTS argument to MAKE-PATHNAME,
PATHNAME-HOST, PATHNAME-DEVICE, PATHNAME-DIRECTORY, PATHNAME-NAME,
PATHNAME-TYPE, PATHNAME-VERSION, NAMESTRING, FILE-NAMESTRING,
DIRECTORY-NAMESTRING, HOST-NAMESTRING, ENOUGH-NAMESTRING, OPEN,
WITH-OPEN-FILE, RENAME-FILE, DELETE-FILE, PROBE-FILE, FILE-WRITE-DATE,
FILE-AUTHOR, LOAD, DIRECTORY, COMPILE-FILE, ED, DRIBBLE, WILD-PATHNAME-P,
PATHNAME-MATCH-P, TRANSLATE-PATHNAME, and COMPILE-FILE-PATHNAME)
recognize logical pathname namestrings is implementation defined.
4. Some real file systems do not have versions. Logical pathname
translation to such a file system ignores the version. This implies that
a program cannot rely on being able to store more than one version of a
file named by a logical pathname.
5. The type of a logical pathname for a Common Lisp source file is "LISP".
This should be translated into whatever type is appropriate in a physical
pathname.
6. The logical pathname host name "SYS" is reserved for the implementation.
The existence and meaning of SYS: logical pathnames is
implementation-defined.
7. File manipulation functions operate with logical pathnames as follows:
7a. The functions OPEN (and WITH-OPEN-FILE), RENAME-FILE, DELETE-FILE,
PROBE-FILE, FILE-WRITE-DATE, FILE-AUTHOR, LOAD, DIRECTORY, COMPILE-FILE,
ED, DRIBBLE, COMPILE-FILE-PATHNAME, and TRUENAME accept logical pathnames
and translate them into physical pathnames, as if by calling the
TRANSLATE-LOGICAL-PATHNAME function.
7b. PATHNAME of a stream created by OPEN (or WITH-OPEN-FILE) of a logical
pathname is a logical pathname.
7c. TRUENAME, PROBE-FILE, and DIRECTORY never return logical pathnames.
7d. RENAME-FILE with a logical pathname as the second argument returns a
logical pathname as the first value.
7e. MERGE-PATHNAMES returns a logical pathname if and only if its first
argument is a logical pathname or its first argument does not specify a
host and the default is a logical pathname.
7f. MAKE-PATHNAME returns a logical pathname if and only if the host is
logical. If the :host argument to MAKE-PATHNAME is supplied, the host is
logical if it came from PATHNAME-HOST of a logical pathname. Whether a
:host argument is logical if it is a string equal to a logical pathname
host name is implementation-defined.
7g. PARSE-NAMESTRING returns a logical pathname according to points 3b
and 3d.
Add these defined names to Common Lisp in support of logical pathnames:
8. LOGICAL-PATHNAME [Class]
LOGICAL-PATHNAME is a subclass of PATHNAME.
9. LOGICAL-PATHNAME pathname [Function]
Converts the argument to a logical pathname and returns it. The
argument can be a logical pathname, a logical pathname namestring
containing a host component, or a stream for which the PATHNAME
function returns a logical pathname. For any other argument,
LOGICAL-PATHNAME signals an error of type TYPE-ERROR.
10. TRANSLATE-LOGICAL-PATHNAME pathname &key [Function]
Translates a logical pathname to the corresponding physical pathname.
The pathname argument is first coerced to a pathname. If it is not a
pathname, string, or file stream an error of type TYPE-ERROR is
signalled.
If the coerced argument is a physical pathname, it is returned.
If the coerced argument is a logical pathname, the first matching
translation (according to PATHNAME-MATCH-P) of the logical pathname
host is applied, as if by calling TRANSLATE-PATHNAME. If the result is
a logical pathname, this process is repeated. When the result is
finally a physical pathname, it is returned.
If no translation matches, an error of type FILE-ERROR is signalled.
TRANSLATE-LOGICAL-PATHNAME might perform additional translations,
typically to provide translation of file types to local naming
conventions, to accomodate physical file systems with limited length
names, or to deal with special character requirements such as
translating hyphens to underscores or uppercase letters to lowercase.
Any such additional translations are implementation defined. Some
implementations do no additional translations.
There are no specified keyword arguments for
TRANSLATE-LOGICAL-PATHNAME, but implementations are permitted to extend
it by adding keyword arguments. There is one specified return value
from TRANSLATE-LOGICAL-PATHNAME; implementations are permitted to
extend it by returning additional values.
11. LOGICAL-PATHNAME-TRANSLATIONS host [Function]
If <host> is not the host component of a logical pathname and not a
string that has been defined as a logical pathname host name by SETF of
LOGICAL-PATHNAME-TRANSLATIONS, signals an error of type TYPE-ERROR.
Otherwise returns the host's list of translations. Each translation is
a list of at least two elements: from-wildcard and to-wildcard. Any
additional elements are implementation defined. From-wildcard is a
logical pathname whose host is <host>. To-wildcard is a pathname.
Translations are searched in the order listed, so more specific
from-wildcards must precede more general ones.
(SETF (LOGICAL-PATHNAME-TRANSLATIONS host) translations) sets a logical
pathname host's list of translations. If <host> is a string that has
not been previously used as logical pathname host, a new logical
pathname host is defined, otherwise an existing host's translations are
replaced. Logical pathname host names are compared with STRING-EQUAL.
When setting the translations list, each from-wildcard can be a logical
pathname whose host is <host> or a logical pathname namestring
parseable by (PARSE-NAMESTRING string <<host>>), where <<host>>
represents the appropriate object as defined in point 3b. Each
to-wildcard can be anything coercible to a pathname by
(PATHNAME to-wildcard). If to-wildcard coerces to a logical pathname,
TRANSLATE-LOGICAL-PATHNAME will perform repeated translation steps when
it uses it.
Implementations can define additional functions that operate on
logical pathname hosts, for example to specify additional translation
rules or options.
12. LOAD-LOGICAL-PATHNAME-TRANSLATIONS host [Function]
If a logical pathname host named <host> (a string) is already defined,
return NIL. Otherwise, search for a logical pathname host definition
in an implementation defined manner. If none is found, signal an
error. If a definition is found, install it and return T.
The search used by LOAD-LOGICAL-PATHNAME-TRANSLATIONS should be
documented, as logical pathname definitions will be created by users,
not only by Lisp implementors. A typical search technique is to
look in a certain directory for a file whose name is derived from
the host name in an implementation-defined fashion.
13. COMPILE-FILE-PATHNAME pathname &key :output-file [Function]
Returns the pathname that COMPILE-FILE would write into, if given the
same arguments. If the pathname argument is a logical pathname and the
:output-file argument is unspecified, the result is a logical pathname.
If an implementation supports additional keyword arguments to
COMPILE-FILE, COMPILE-FILE-PATHNAME must accept the same arguments.
Examples:
;A very simple example of setting up a logical pathname host. No
;translations are necessary to get around file system restrictions, so
;all that is necessary is to specify the root of the physical directory
;tree that contains the logical file system.
;The namestring syntax on the right-hand side is implementation-specific.
(setf (logical-pathname-translations "foo")
'(("**;*.*.*" "MY-LISPM:>library>foo>**>")))
;Sample use of that logical pathname. All return values
;are of course implementation-specific.
(translate-logical-pathname "foo:bar;baz;mum.quux.3")
=> MY-LISPM:>library>foo>bar>baz>mum.quux.3
;A more complex example, dividing the files among two file servers
;and several different directories. This Unix doesn't support
;:WILD-INFERIORS in the directory, so each directory level must
;be translated individually. No file name or type translations
;are required except for .MAIL to .MBX.
;The namestring syntax on the right-hand side is implementation-specific.
(setf (logical-pathname-translations "prog")
'(("RELEASED;*.*.*" "MY-UNIX:/sys/bin/my-prog/")
("RELEASED;*;*.*.*" "MY-UNIX:/sys/bin/my-prog/*/")
("EXPERIMENTAL;*.*.*" "MY-UNIX:/usr/Joe/development/prog/")
("EXPERIMENTAL;DOCUMENTATION;*.*.*"
"MY-VAX:SYS$DISK:[JOE.DOC]")
("EXPERIMENTAL;*;*.*.*" "MY-UNIX:/usr/Joe/development/prog/*/")
("MAIL;**;*.MAIL" "MY-VAX:SYS$DISK:[JOE.MAIL.PROG...]*.MBX")))
;Sample use of that logical pathname. All return values
;are of course implementation-specific.
(translate-logical-pathname "prog:mail;save;ideas.mail.3")
=> MY-VAX:SYS$DISK:[JOE.MAIL.PROG.SAVE]IDEAS.MBX.3
;Example translations for a program that uses three files main.lisp,
;auxiliary.lisp, and documentation.lisp. These translations might be
;supplied by a software supplier as examples.
;For Unix with long file names
(setf (logical-pathname-translations "prog")
'(("CODE;*.*.*" "/lib/prog/")))
;Sample use of that logical pathname. All return values
;are of course implementation-specific.
(translate-logical-pathname "prog:code;documentation.lisp")
=> /lib/prog/documentation.lisp
;For Unix with 14-character file names, using .lisp as the type
(setf (logical-pathname-translations "prog")
'(("CODE;DOCUMENTATION.*.*" "/lib/prog/docum.*")
("CODE;*.*.*" "/lib/prog/")))
;Sample use of that logical pathname. All return values
;are of course implementation-specific.
(translate-logical-pathname "prog:code;documentation.lisp")
=> /lib/prog/docum.lisp
;For Unix with 14-character file names, using .l as the type
;The second translation shortens the compiled file type to .b
(setf (logical-pathname-translations "prog")
`(("**;*.LISP.*" ,(logical-pathname "PROG:**;*.L.*"))
(,(compile-file-pathname (logical-pathname "PROG:**;*.LISP.*"))
,(logical-pathname "PROG:**;*.B.*"))
("CODE;DOCUMENTATION.*.*" "/lib/prog/documentatio.*")
("CODE;*.*.*" "/lib/prog/")))
;Sample use of that logical pathname. All return values
;are of course implementation-specific.
(translate-logical-pathname "prog:code;documentation.lisp")
=> /lib/prog/documentatio.l
;For a Cray with 6 character names and no directories, types, or versions.
(setf (logical-pathname-translations "prog")
(let ((l '(("MAIN" "PGMN")
("AUXILIARY" "PGAUX")
("DOCUMENTATION" "PGDOC")))
(logpath (logical-pathname "prog:code;"))
(phypath (pathname "XXX")))
(append
;; Translations for source files
(mapcar #'(lambda (x)
(let ((log (first x))
(phy (second x)))
(list (make-pathname :name log
:type "LISP"
:version :wild
:defaults logpath)
(make-pathname :name phy
:defaults phypath))))
l)
;; Translations for compiled files
(mapcar #'(lambda (x)
(let* ((log (first x))
(phy (second x))
(com (compile-file-pathname
(make-pathname :name log
:type "LISP"
:version :wild
:defaults logpath))))
(setq phy (concatenate 'string phy "B"))
(list com
(make-pathname :name phy
:defaults phypath))))
l))))
;Sample use of that logical pathname. All return values
;are of course implementation-specific.
(translate-logical-pathname "prog:code;documentation.lisp")
=> PGDOC
Rationale:
1. Large programs can be moved between sites without changing any
pathnames, provided all pathnames used are logical. A portable system
construction tool can be created that operates on programs defined as
sets of files named by logical pathnames.
2. Logical pathname syntax was chosen to be easily translated into most
popular file systems, while still being powerful enough for storing large
programs. Although they have hierarchical directories, extended wildcard
matching, versions, and no limit on the length of names, they can be
mapped onto a less capable real file file system by translating each
directory that is used into a flat directory name, doing wildcards in
Lisp rather than in the file system, treating all versions as :newest,
and/or using translations to shorten long names.
Logical pathname words are restricted to non-case-sensitive letters,
digits, and hyphens to avoid creating problems with real file systems
that support limited character sets for file naming. Other characters
could have been mapped onto such file systems through translations, but
that didn't seem worth the trouble. Logical pathnames have to be
non-case-sensitive or it would be very difficult to map them onto a
non-case-sensitive file system.
Features such as :UP and :BACK relative directories and a namestring
syntax for the root directory were not felt to be necessary in logical
pathnames. They could be added later if a need emerges.
It is not a goal of logical pathnames to be able to represent all
possible file names. Their goal is rather to represent just enough file
names to be useful for storing software. Real pathnames, in contrast,
need to provide a uniform interface to all possible file names, including
names and naming conventions that are not under the control of Common
Lisp.
The choice of logical pathname syntax, using colon, semicolon, and
period, was guided by the goals of being visually distinct from real file
systems and minimizing the use of special characters.
The consequences of using any value not specified here as a logical
pathname component are unspecified, for the benefit of the Explorer.
3. The LOGICAL-PATHNAME function is separate from the PATHNAME function
so that the syntax of logical pathname namestrings does not constrain the
syntax of physical pathname namestrings in any way. Logical pathname
syntax must be defined by Common Lisp so that logical pathnames can be
conveniently exchanged between implementations, but physical pathname
syntax is dictated by forces outside our control.
3b,c. Allowing PARSE-NAMESTRING and MERGE-PATHNAMES to recognize logical
pathname namestrings in these situations provides for natural operations
on logical pathnames. Frequently a string containing just a name, or a
name and a type, will be recognized as a logical pathname by merging it
against a default containing a logical pathname host and directory.
3d. Recognition of logical pathname namestrings by PATHNAME and related
functions is left up to each implementation because some implementations
definitely require this, other implementations don't want to do this, and
nobody wants to change. In any case, Common Lisp historically has avoided
saying anything about the syntax of the strings accepted by the PATHNAME
function, and point 3d preserves that position.
3b,7f. Leaving it implementation defined whether a string, used as the
host argument to PARSE-NAMESTRING or the :host argument to MAKE-PATHNAME,
can be recognized as logical pathname host name is for the same reason as
point 3d. It allows each implementation to decide whether there is one
namespace or two. The correct way to write this is:
(MAKE-PATHNAME :HOST (PATHNAME-HOST (LOGICAL-PATHNAME "hostname:"))
...)
4. Logical pathname versions could have been supported on real file
systems that do not have versions by defining a kind of translation to
encode the version number in the name. However, the typical use of
versions is such that on a file system without versions, people would
rather just store one version of a file, and not preserve the version
information by encoding it somehow in the name. This is different from
the typical use of types or directories, where the files with different
values in those components are truly distinct and everything would break
if you only kept one file.
5,13. The COMPILE-FILE-PATHNAME function and the specification of "LISP"
as the type of a logical pathname for a Common Lisp source file together
provide enough information about compilation for a portable system
construction tool that uses logical pathnames to work. Suppose you want
to call COMPILE-FILE only if the source file is newer than the compiled
file. To do that, you have to have a way to know the name of the
compiled file without actually calling COMPILE-FILE.
No standard file type for compiler output is proposed, because in some
implementations the compiler produces one of several file types,
depending on a variety of implementation-dependent circumstances.
COMPILE-FILE-PATHNAME provides access to the "default[ing] in a manner
appropriate to the implementation's file system conventions" mentioned in
the CLtL documentation of COMPILE-FILE.
6. The use of the logical pathname host name "SYS" for the implementation
is current practice. Standardizing on this name helps users choose
logical pathname host names that avoid conflicting with
implementation-defined names.
7. Accepting logical pathnames for file access is a natural extension
of the file access functions and makes it easier to program using only
logical pathnames in situations where that is appropriate.
8. The LOGICAL-PATHNAME class exists so that methods can distinguish
logical pathnames from regular pathnames.
9. See point 3 above.
10. TRANSLATE-LOGICAL-PATHNAME is the heart of the logical pathname
feature. Allowing TRANSLATE-LOGICAL-PATHNAME on a physical pathname,
simply returning the argument, makes some programs easier to write.
Additional implementation defined translations make it possible for
implementations with unusual file systems to offer some help to the user
in setting up the translations for a logical pathname host, by handling
some of the work automatically. Logical pathnames that translate to
other logical pathnames are a feature that several people have requested.
11. SETF of LOGICAL-PATHNAME-TRANSLATIONS is a simple way for a user to
define a new logical pathname host. Using SETF makes it possible to add
to or modify the translations of an existing logical pathname host.
It is always up to the person who writes the translation rules for a
particular logical pathname host to a particular physical file system to
make sure that the logical pathnames that are actually going to be used
translate to valid pathnames for the particular file system, and that
no two logical pathnames that are supposed to be distinct translate to
the same physical pathname.
12. Loading of logical pathname translations from a site-dependent file
allows software to be distributed using logical pathnames. The assumed
model of software distribution is a division of labor between the
supplier of the software and the user installing it. The supplier
chooses logical pathnames to name all the files used or created by the
software, and supplies examples of logical pathname translations for a
few popular file systems. Each example uses an assumed directory and/or
device name, assumes local file naming conventions, and provides
translations that will translate all the logical pathnames used or
generated by the particular software into valid physical pathnames.
For a powerful file system these translations can be quite simple. For
a more restricted file system, it may be necessary to list an explicit
translation for every logical pathname used, for example when dealing
with restrictions on the maximum length of a file name.
The user installing the software decides on which device and/or directory
to store the files and edits the example logical pathname translations
accordingly. If necessary, the user also adjusts the translations for
local file naming conventions and any other special aspects of the user's
local file system policy and local Common Lisp implementation. For
example, the files might be divided among several file server hosts to
share the load. The process of defining site-customized logical pathname
translations is quite easy for a user of a popular file system for which
the software supplier has provided an example. A user of a more unusual
file system might have to take more time; the supplier can help by
providing a list of all the logical pathnames used or generated by the
software.
Once the user has created a suitable SETF of LOGICAL-PATHNAME-TRANSLATIONS
form, he can evaluate that form and then load and run the software. It
may be necessary to use the translations again, or on another workstation
at the same site, so it is best to save the SETF form in the standard
place where it can be found later by LOAD-LOGICAL-PATHNAME-TRANSLATIONS.
Often a software supplier will include a program for restoring software
from the distribution medium to the file system, and a program for loading
the software from the file system into a Common Lisp, and these programs
will start by calling LOAD-LOGICAL-PATHNAME-TRANSLATIONS to make sure that
the logical pathname host is defined.
Note that the SETF of LOGICAL-PATHNAME-TRANSLATIONS form isn't part of
the program, it's separate. It's written by the user, not by the
software supplier. That separation, and a uniform convention for how to
do the separation, are the key aspects of logical pathnames. For small
programs involving only a handful of files, it doesn't matter much. The
real benefits come with large programs with hundreds or thousands of
files and more complicated situations such as program-generated file
names or porting a program developed on a system with long file names
onto a system with a very restrictive limit on the length of file names.
Current practice:
Symbolics Genera has had a similar facility for many years. It is used
extensively for software distribution by Symbolics and its customers.
The Genera facility uses the same logical pathname syntax but different
function names, and is somewhat more complicated. The extra complexity
is not necessary in the Common Lisp standard.
The T.I. Explorer also has a comparable logical pathname facility,
although the translation mechanism is unfortunately less general than
proposed here. The namestring syntax used is slightly different:
host ":" [{directory "."}* directory ";"] [name] ["." type] ["#" version]
The newest version is indicated by ">" instead of "newest".
Macintosh Allegro Common Lisp) has a logical pathname feature which is
somewhat simpler but aimed at solving the same problems. It has logical
directory names, to simplify access to sets of files in differently named
directories (an especially severe problem on micros where everybody just
has to have a different pet name for their hard disk). This isn't really
the same as simplifying access to different file systems, although of
course solving the latter automatically solves the former. In general,
access to different file systems requires translating names and types,
not just translating directories.
Symbolics Genera offers a function for translating from a physical
pathname back to a logical pathname. There are a number of problems with
this, and so it has not been proposed here. An earlier version specified
TRANSLATE-LOGICAL-PATHNAME to return enough information to allow the user
program to perform the backtranslation itself, but that hsd problems
so it was removed.
The Genera equivalent of LOAD-LOGICAL-PATHNAME-TRANSLATIONS looks for
a file named SYS:SITE;hostname.TRANSLATIONS.
Current practice in Genera, Explorer, and Macintosh has one namespace for
both logical and physical namestrings. This proposal allows an
implementation to choose to have one namespace or to have two separate
namespaces for namestrings.
Cost to Implementors:
This is a fairly complex facility, but its performance is unimportant
so a straightforward implementation should suffice. Most of the
complexity comes in dealing with unusual file systems, such as ones
that don't allow long file names.
Cost to Users:
None.
Cost of non-adoption:
Portable software construction and distribution will have to rely on
implementation-dependent kludges. Lisp software will continue to be
difficult to install.
Performance impact:
None.
Benefits:
Avoid cost of non-adoption.
Esthetics:
Improved portability of large programs.
Discussion:
Issue PATHNAME-LOGICAL fundamentally depends on issue PATHNAME-WILD. If
PATHNAME-WILD:NEW-FUNCTIONS does not pass, PATHNAME-LOGICAL cannot pass.
If PATHNAME-CANONICAL-TYPE:NEW-CONCEPT passes, it will affect the
behavior of the function TRANSLATE-PATHNAME and therefore the behavior of
the function TRANSLATE-LOGICAL-PATHNAME. When a logical pathname
translation has from-wildcard and to-wildcard type components that are
:WILD or omitted, translation of the type will be guided by canonical
types. If PATHNAME-CANONICAL-TYPE:NEW-CONCEPT fails to pass, it will
either have to be done behind the scenes by TRANSLATE-PATHNAME or users
will have to write more verbose translations that individually specify
the handling of each file type (as shown in some of the examples here).
∂23-Jun-89 1052 X3J13-mailer Issue: PATHNAME-WILD (version 7)
Received: from STONY-BROOK.SCRC.Symbolics.COM by SAIL.Stanford.EDU with TCP; 23 Jun 89 10:51:51 PDT
Received: from KENNETH-WILLIAMS.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via INTERNET with SMTP id 616035; 23 Jun 89 13:53:42 EDT
Date: Fri, 23 Jun 89 13:52 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Issue: PATHNAME-WILD (version 7)
To: X3J13@sail.stanford.edu
Message-ID: <19890623175202.6.MOON@KENNETH-WILLIAMS.SCRC.Symbolics.COM>
This issue is on the agenda for the June X3J13 meeting. KMP and I
have prepared a revised writeup which we think is ready for release.
This version has been updated based on last minute discussion:
Remove reversible argument from TRANSLATE-PATHNAME, add ability for
implementations to add keyword arguments and extra return values.
Issue: PATHNAME-WILD
Forum: Cleanup
References: Pathnames (pp410-413)
Related issues: PATHNAME-COMPONENT-VALUE, PATHNAME-LOGICAL
Category: ADDITION
Edit history: 21-Jul-88, Version 1 by Pitman
06-Oct-88, Version 2 by Pitman
9-May-89, Version 3 by Moon (small fixes)
10-May-89, Version 4 by Moon (add two more functions)
13-May-89, Version 5 by Moon (minor cleanups, add clarification)
19-Jun-89, Version 6 by Moon (revise based on extensive
discussion in the cleanup subcommittee; rewrite
the description of TRANSLATE-PATHNAME so it is
possible to understand it)
23-Jun-89, Version 7 by Moon (simplify TRANSLATE-PATHNAME
based on last minute discussion of logical pathnames)
Problem Description:
Some file systems provide more complex conventions for wildcards than
simple component-wise wildcards (:WILD). For example,
"F*O" might mean:
- a normal three character name
- a three-character name, with the middle char wild
- at least a two-character name, with the middle 0 or more chars wild
- a wild match spanning multiple directories
">foo>*>bar" might imply:
- the middle directory is named "*"
- the middle directory is :WILD
- there may be zero or more :WILD middle directories
- the middle directory name matches any one-letter name
">foo>**>bar" might mean
- the middle directory is named "**"
- the middle directory is :WILD
- there may be zero or more :WILD middle directories
- the middle directory name matches any two-letter name
Some file systems support even more complex wildcards, for example
regular expressions.
The CL pathname model does not specify a way to represent complex
wildcards, which means, for example, that (MAKE-PATHNAME :NAME "F*O")
cannot be recognized by portable code as containing a wildcard.
Common Lisp provides only the first of these four common operations
on wildcard pathnames:
(1) Enumerate the set of existing files that match the pathname;
this is provided by the DIRECTORY function.
(2) Test whether a pathname contains wildcards.
(3) Test whether a pathname matches a wildcard pathname.
(4) Translate one pathname into another according to a mapping specified
by a pair of wildcard pathnames.
Proposal (PATHNAME-WILD:NEW-FUNCTIONS):
Introduce the following three functions:
1. WILD-PATHNAME-P pathname &optional field-key
Tests a pathname for the presence of wildcard components. If the first
argument is not a pathname, string, or file stream an error of type
TYPE-ERROR is signalled.
If no <field-key> is provided, or the <field-key> is NIL, the result is
T if <pathname> has any wildcard components, NIL if <pathname> has none.
If a non-null <field-key> is provided, it must be one of :HOST, :DEVICE,
:DIRECTORY, :NAME, :TYPE, or :VERSION. In this case, the result is T
if the indicated component of <pathname> is a wildcard, NIL if the
component is not a wildcard. Note that not all implementations
support wildcards in all fields, according to PATHNAME-COMPONENT-VALUE.
2. PATHNAME-MATCH-P pathname wildcard
T if <pathname> matches <wildcard>, otherwise NIL. The matching rules
are implementation-defined but should be consistent with the
DIRECTORY function. Missing components of <wildcard> default to :WILD.
If either argument is not a pathname, string, or file stream an error
of type TYPE-ERROR is signalled. It is valid for <pathname> to be a
wild pathname; a wildcard field in <pathname> will only match a
wildcard field in <wildcard>, i.e. the function is not commutative.
It is valid for <wildcard> to be a non-wild pathname.
3. TRANSLATE-PATHNAME source from-wildcard to-wildcard &key
Translates the pathname <source>, which matches <from-wildcard>, into
a corresponding pathname <result>, which matches <to-wildcard>, and
returns <result>.
The pathname <result> is <to-wildcard> with each wildcard or missing
field replaced by a portion of <source>. A "wildcard field" is a
pathname component with a value of :WILD, a :WILD element of a
list-valued directory component, or an implementation-defined portion
of a component, such as the "*" in the complex wildcard string
"foo*bar" that some implementations support. An implementation that
adds other wildcard features, such as regular expressions, must define
how TRANSLATE-PATHNAME extends to those features. A "missing field" is
a pathname component with a value of NIL.
The portion of <source> that is copied into <result> is implementation
defined. Typically it is determined by the user interface conventions
of the file systems involved. Usually it is the portion of <source>
that matches a wildcard field of <from-wildcard> that is in the same
position as the wildcard or missing field of <to-wildcard>. If there
is no wildcard field in <from-wildcard> at that position, then usually
it is the entire corresponding pathname component of <source>, or in
the case of a list-valued directory component, the entire corresponding
list element. For example, if the name components of <source>,
<from-wildcard>, and <to-wildcard> are "gazonk", "gaz*", and "h*"
respectively, then in most file systems, the wildcard fields of the
name component of <from-wildcard> and <to-wildcard> are each "*", the
matching portion of <source> is "onk", and the name component of
<result> is "honk". However, the exact behavior of TRANSLATE-PATHNAME
cannot be dictated by the Common Lisp language and must be allowed to
vary, depending on the user interface conventions of the file systems
involved.
During the copying of a portion of <source> into <result>, additional
implementation-defined translations of alphabetic case or file naming
conventions might occur, especially when <from-wildcard> and
<to-wildcard> are for different hosts.
If any of the first three arguments is not a pathname, string, or file
stream an error of type TYPE-ERROR is signalled. It is valid for
<source> to be a wild pathname; in general this will produce a wild
result. It is valid for <from-wildcard> and/or <to-wildcard> to be
non-wild pathnames. (PATHNAME-MATCH-P <source> <from-wildcard>) must
be true or an error is signalled.
There are no specified keyword arguments for TRANSLATE-PATHNAME, but
implementations are permitted to extend it by adding keyword arguments.
There is one specified return value from TRANSLATE-PATHNAME;
implementations are permitted to extend it by returning additional
values.
Implementation guideline: one file system performs this operation by
examining each piece of the three pathnames in turn, where a piece is a
pathname component or a list element of a structured component such as
a hierarchical directory. Hierarchical directory elements in
<from-wildcard> and <to-wildcard> are matched by whether they are
wildcards, not by depth in the directory hierarchy. If the piece in
<to-wildcard> is present and not wild, it is copied into the result.
If the piece in <to-wildcard> is :WILD or NIL, the piece in <source> is
copied into the result. Otherwise, the piece is <to-wildcard> might be
a complex wildcard such as "foo*bar" and the piece in <from-wildcard>
should be wild; the portion of the piece in <source> that matches the
wildcard portion of the piece in <from-wildcard> replaces the wildcard
portion of the piece in <to-wildcard> and the value produced is used in
the result.
4. Clarify that the functions OPEN (and WITH-OPEN-FILE), PROBE-FILE,
FILE-WRITE-DATE, FILE-AUTHOR, and TRUENAME only accept non-wildcard
pathnames and signal an error if given a pathname for which
WILD-PATHNAME-P returns true.
5. Clarify that the functions RENAME-FILE, DELETE-FILE, LOAD, and
COMPILE-FILE have implementation-defined consequences when given a
wildcard pathname. Each function might signal an error or might operate
on all files that match the wildcard pathname.
Examples:
;The following examples are not portable. They are written to run
;with particular file systems and particular wildcard conventions.
;Other implementations will behave differently. These examples are
;intended to be illustrative, not to be prescriptive.
(WILD-PATHNAME-P (MAKE-PATHNAME :NAME :WILD)) => T
(WILD-PATHNAME-P (MAKE-PATHNAME :NAME :WILD) :NAME) => T
(WILD-PATHNAME-P (MAKE-PATHNAME :NAME :WILD) :TYPE) => NIL
(WILD-PATHNAME-P (PATHNAME "S:>foo>**>")) => T ;Lispm
(WILD-PATHNAME-P (PATHNAME :NAME "F*O")) => T ;Most places
;This example assumes one particular set of wildcard conventions
;Not all file systems will run this example exactly as written
(DEFUN RENAME-FILES (FROM TO)
(DOLIST (FILE (DIRECTORY FROM))
(RENAME-FILE FILE (TRANSLATE-PATHNAME FILE FROM TO))))
(RENAME-FILES "/usr/me/*.lisp" "/dev/her/*.l")
;Renames /usr/me/init.lisp to /dev/her/init.l
(RENAME-FILES "/usr/me/pcl*/*" "/sys/pcl/*/")
;Renames /usr/me/pcl-5-may/low.lisp to /sys/pcl/pcl-5-may/low.lisp
;In some file systems the result might be /sys/pcl/5-may/low.lisp
(RENAME-FILES "/usr/me/pcl*/*" "/sys/library/*/")
;Renames /usr/me/pcl-5-may/low.lisp to /sys/library/pcl-5-may/low.lisp
;In some file systems the result might be /sys/library/5-may/low.lisp
(RENAME-FILES "/usr/me/foo.bar" "/usr/me2/")
;Renames /usr/me/foo.bar to /usr/me2/foo.bar
(RENAME-FILES "/usr/joe/*-recipes.text" "/usr/jim/cookbook/joe's-*-rec.text")
;Renames /usr/joe/lamb-recipes.text to /usr/jim/cookbook/joe's-lamb-rec.text
;Renames /usr/joe/pork-recipes.text to /usr/jim/cookbook/joe's-pork-rec.text
;Renames /usr/joe/veg-recipes.text to /usr/jim/cookbook/joe's-veg-rec.text
;This example assumes one particular set of wildcard conventions
(PATHNAME-NAME (TRANSLATE-PATHNAME "foobar" "foo*" "*baz")) => "barbaz"
(PATHNAME-NAME (TRANSLATE-PATHNAME "foobar" "foo*" "*")) => "foobar"
(PATHNAME-NAME (TRANSLATE-PATHNAME "foobar" "*" "foo*")) => "foofoobar"
(PATHNAME-NAME (TRANSLATE-PATHNAME "bar" "*" "foo*")) => "foobar"
;Using Unix syntax and the wildcard conventions used by the
;particular version of Unix on which I tried this:
(NAMESTRING
(TRANSLATE-PATHNAME "/usr/dmr/hacks/frob.l"
"/usr/d*/hacks/*.l"
"/usr/d*/backup/hacks/backup-*.*"))
=> "/usr/dmr/backup/hacks/backup-frob.l"
(NAMESTRING
(TRANSLATE-PATHNAME "/usr/dmr/hacks/frob.l"
"/usr/d*/hacks/fr*.l"
"/usr/d*/backup/hacks/backup-*.*"))
=> "/usr/dmr/backup/hacks/backup-ob.l"
;This is similar to the above example but uses two different hosts,
;U: which is a Unix and V: which is a VMS. Note the translation
;of file type and alphabetic case conventions.
(NAMESTRING
(TRANSLATE-PATHNAME "U:/usr/dmr/hacks/frob.l"
"U:/usr/d*/hacks/*.l"
"V:SYS$DISK:[D*.BACKUP.HACKS]BACKUP-*.*"))
=> "V:SYS$DISK:[DMR.BACKUP.HACKS]BACKUP-FROB.LSP"
(NAMESTRING
(TRANSLATE-PATHNAME "U:/usr/dmr/hacks/frob.l"
"U:/usr/d*/hacks/fr*.l"
"V:SYS$DISK:[D*.BACKUP.HACKS]BACKUP-*.*"))
=> "V:SYS$DISK:[DMR.BACKUP.HACKS]BACKUP-OB.LSP"
;This example presumes background information described in PATHNAME-LOGICAL
(DEFUN TRANSLATE-LOGICAL-PATHNAME-1 (PATHNAME RULES)
(LET ((RULE (ASSOC PATHNAME RULES :TEST #'PATHNAME-MATCH-P)))
(UNLESS RULE (ERROR "No translation rule for ~A" PATHNAME))
(TRANSLATE-PATHNAME PATHNAME (FIRST RULE) (SECOND RULE))))
(TRANSLATE-LOGICAL-PATHNAME-1 "FOO:CODE;BASIC.LISP"
'(("FOO:DOCUMENTATION;" "MY-UNIX:/doc/foo/")
("FOO:CODE;" "MY-UNIX:/lib/foo/")
("FOO:PATCHES;*;" "MY-UNIX:/lib/foo/patch/*/")))
=> the pathname MY-UNIX:/lib/foo/basic.l
Rationale:
1,2,3. These three functions provide a standardized interface to the
idiosyncratic wildcard functionality of each host file system.
1. WILD-PATHNAME-P makes it possible to detect wild pathnames reliably and
do something useful (give up, merge out the bothersome components, call
DIRECTORY for a list of matching pathnames, etc.)
2,3. TRANSLATE-PATHNAME is needed by many application programs that deal
with wildcard pathnames. PATHNAME-MATCH-P and TRANSLATE-PATHNAME are
needed by logical pathnames. The PATHNAME-LOGICAL proposal cannot be
implemented without these features. Implementing PATHNAME-LOGICAL could
involve adding additional capabilities to TRANSLATE-PATHNAME, depending
on the type of file system used, but those capabilities do not need to
be in the standard.
4. Since these functions return a value connected with one file, there
is no meaningful way to extend them to work on wildcard pathnames. It
seems best to specify that they signal an error, rather than leaving
the consequences undefined.
5. The consequences are proposed to be implementation-defined because
current practice varies and no one wants to change.
Current Practice:
Presumably no implementation supports the proposal exactly as stated.
Symbolics Genera has had similar features under different names for many
years:
(SEND pathname :WILD-P) returns a value such as NIL, :NAME, :TYPE,
etc., indicating the first wild field.
(SEND pathname :NAME-WILD-P), (SEND pathname :DIRECTORY-WILD-P),
etc. test individual fields.
The :TRANSLATE-WILD-PATHNAME, :TRANSLATE-WILD-PATHNAME-REVERSIBLE, and
:PATHNAME-MATCH messages resemble TRANSLATE-PATHNAME and
PATHNAME-MATCH-P.
The Explorer also supports the messages :WILD-P (although it only
returns NIL or T), :NAME-WILD-P, etc., :TRANSLATE-WILD-PATHNAME, and
:PATHNAME-MATCH.
Points 4 and 5 are current practice as far as the authors are aware.
The Explorer permits DELETE-FILE on a wild pathname, meaning to delete
all files that match.
Cost to Implementors:
Many implementations probably have a substrate which is capable of this
or something similar already. In such cases, it's a relatively small
matter to add the proposed interface.
Even in cases where an implementation doesn't have ready code, it's clearly
better for the implementor to write that code once and for all than to ask
each user of wildcards to write it.
Since the detailed behavior is at the implementor's discretion, the cost
is unlikely to be large. Some file systems will do all the work and the
implementor need only provide an interface to the file system or to a
standard library routine. For other file systems the implementor has to
write the actual matching and translation algorithms.
Cost to Users:
None. This change is upward compatible.
Cost of Non-Adoption:
Wild pathnames would continue to be mistaken for ordinary pathnames in
many situations. User programs that deal with wildcard pathnames would
have to operate on implementation-dependent representations and hence
would not be easily portable.
The biggest cost is that the logical pathnames proposal would be stymied.
Performance Impact:
None.
Benefits:
A more complete set of wildcard pathname operations. Portable user
programs that deal with wildcard pathnames will be more consistent
and reliable. A portable system construction tool can be written
and the foundations are laid for a `logical pathname' facility
(proposed separately in PATHNAME-LOGICAL).
Aesthetics:
This change would make some portable code less kludgey.
Discussion:
There was some question about the name. The name PATHNAME-WILD-P
suggests a ``slot'' of a pathname (like PATHNAME-HOST),
while WILD-PATHNAME-P suggests a type (like INPUT-STREAM-P).
The committee was split on what to call it. Since it is more
like a type than a slot, the name WILD-PATHNAME-P was chosen.
It's been suggested that WILD-PATHNAME-P and PATHNAME-MATCH-P be allowed
to return a value other than T to represent "truth", which would
somehow encode some additional information.
∂23-Jun-89 1234 X3J13-mailer issue CLOS-MACRO-COMPILATION, version 5
Received: from cs.utah.edu by SAIL.Stanford.EDU with TCP; 23 Jun 89 12:34:23 PDT
Received: from defun.utah.edu by cs.utah.edu (5.61/utah-2.1-cs)
id AA00110; Fri, 23 Jun 89 13:34:46 -0600
Received: by defun.utah.edu (5.61/utah-2.0-leaf)
id AA03741; Fri, 23 Jun 89 13:34:43 -0600
Date: Fri, 23 Jun 89 13:34:43 -0600
From: sandra%defun@cs.utah.edu (Sandra J Loosemore)
Message-Id: <8906231934.AA03741@defun.utah.edu>
To: x3j13@sail.stanford.edu
Reply-To: cl-compiler@sail.stanford.edu
Subject: issue CLOS-MACRO-COMPILATION, version 5
This is a new version of an issue that was distributed last week. I
have made some changes to clarify some confusing wording, that are not
supposed to affect the content of the proposal. I hope this is ready
to vote on now.
Forum: Compiler
Issue: CLOS-MACRO-COMPILATION
References: CLOS chapters 1 & 2 (88-002R)
CLOS chapter 3 (89-003)
Issue COMPILE-FILE-HANDLING-OF-TOP-LEVEL-FORMS
Issue DEFINING-MACROS-NON-TOP-LEVEL
Category: CLARIFICATION
Edit History: V1, 10 Mar 1989, Sandra Loosemore
V2, 13 Mar 1989, Sandra Loosemore
V3, 21 Mar 1989, Sandra Loosemore (fix error language)
V4, 11 Jun 1989, Sandra Loosemore (Gregor's amendment)
V5, 23 Jun 1989, Sandra Loosemore (wording changes per Pitman)
Status: Ready for release
Problem Description:
Do the CLOS defining macros (DEFCLASS, DEFMETHOD, DEFGENERIC, and
DEFINE-METHOD-COMBINATION) have compile-time side-effects similar
to those for DEFSTRUCT or DEFMACRO?
A part of the problem is that we do not currently have a full
understanding of all the issues involved. In particular, work on
defining the CLOS meta-object protocol is still in progress. The goal
of this proposal is to say enough about the behavior of these macros
in the standard so that users can use them portably in compiled code,
but to leave as much of the behavior as possible unspecified to avoid
placing undue restrictions on the meta-object protocol.
Proposal CLOS-MACRO-COMPILATION:MINIMAL:
State that top-level calls to the CLOS defining macros have the
following compile-time side-effects. Any other compile-time behavior
is explicitly left unspecified.
DEFCLASS:
* The class name may appear in subsequent type declarations.
* The class name can be used as a specializer in subsequent
DEFMETHOD forms.
DEFGENERIC:
* The generic function can be referenced in subsequent DEFMETHOD forms.
* DEFGENERIC does not arrange for the generic function to be callable
at compile time.
DEFMETHOD:
* DEFMETHOD does not arrange for the method to be callable at compile
time. If there is a generic function with the same name defined at
compile time, compiling a DEFMETHOD does not add the method to that
generic function. (That is, the method is added to the generic
function only when the DEFMETHOD is actually executed.)
The error-signalling behavior described in the specification of
DEFMETHOD in CLOS chapter 2 (if the function isn't a generic function
or if the lambda-list is not congruent) happens only when the defining
form is executed, not at compile time.
The forms in EQL specializers are evaluated when the defining form
is executed. The compiler is permitted to build in knowledge
about what the form in an EQL specializer will evaluate to in cases
where the ultimate result can be syntactically inferred without
actually evaluating it.
DEFINE-METHOD-COMBINATION:
* The method combination can be used in subsequent DEFGENERIC forms.
The body of a DEFINE-METHOD-COMBINATION form is evaluated no earlier
than when the defining macro is executed and possibly as late as
generic function invocation time. The compiler may attempt to
evaluate these forms at compile time but must not depend on being able
to do so.
Rationale:
The compile-time behavior of DEFCLASS is similar to DEFSTRUCT or
DEFTYPE.
DEFGENERIC and DEFMETHOD are similar to DEFUN, which doesn't add the
function definition to the compile-time environment. Since generic
functions may be freely redefined between compile and run time (just
like any other function), a method may end up "belonging" to a
different generic function at load time than at compile time. This
is why it is inappropriate to signal errors about congruency problems
(etc) until the method is actually added to the generic function at
run time.
Current Practice:
The items listed under DEFCLASS in proposal MINIMAL are fairly standard
programming style.
Flavors does not support compile-time instantiation of classes. It
does not make method combinations available at compile-time either, but
Moon considers that to be a bad design choice.
Cost to implementors:
Unknown.
Cost to users:
Unknown, but probably fairly small.
Wrapping an (EVAL-WHEN (EVAL COMPILE LOAD) ...) around the appropriate
definitions will make sure they are fully defined at compile-time.
Alternatively, the definitions could be placed in a separate file,
which is loaded before compiling the file that depends on those
definitions.
Benefits:
Programmers can rely on programs that use the CLOS defining macros
being able to compile correctly in all implementations, without having
to wrap explicit EVAL-WHENs around every macro call.
Discussion:
This writeup is based on discussions between Moon, Gray, and
Loosemore, who are mostly in agreement on the things presented in
proposal MINIMAL. We have purposely avoided saying anything about
whether meta-objects representing the classes, methods, etc. get
created at compile-time, or whether such meta-objects are fully or
partially defined. The basic questions addressed by this issue are
what kinds of things can be defined and then used during compilation
of the same file that defines them, and what restrictions might apply.
These proposals are not completely compatible with the meta-object
protocol document (89-003). Gregor Kiczales says:
No one believes that what is written in draft 10 of the MOP is valid.
Sandra Loosemore says:
Although I admit I don't understand all of the issues involved with
the meta-object protocol, I prefer proposal MINIMAL over
NOT-SO-MINIMAL. I don't think leaving the issue of whether or not
classes can be instantiated at compile-time unspecified places an
undue burden on users, and it does leave more freedom for the
meta-object protocol to decide what the right behavior really is.
Dick Gabriel notes:
The question I have about the process going on with respect to the
CLOS-MACRO-COMPILATION issue is whether the fine-grained behavior of
CLOS under various compilation/evaluation situations is being
over-specified.
At this stage of the game I worry that we might go a little too far in
one direction in specification when we are actually engaged in design
work. This isn't intended to be a criticism of any committees, but I
would feel a lot more comfortable with a conservative specification
that defined well-formed programs being loaded or compiled in fresh
Common Lisps with a pretty simple eval-when model that is easier to
specify and which makes it easy for all but the hairiest
compilation-environment-frobbing programs to be written.